import type {Component, VNode} from 'vue';
import {h, nextTick, ref, render} from 'vue';

import type {Recordable} from '#/components/common/core/typings';

import type {AlertProps, BeforeCloseScope, PromptProps} from './alert';

import {useSimpleLocale} from '#/components/common/effects/hooks';
import {Input, BasicRenderContent} from '#/components/common/core/ui-kit/shadcn-ui';
import {isFunction, isString} from '#/components/common/utils';

import Alert from './alert.vue';

const alerts = ref<Array<{ container: HTMLElement; instance: Component }>>([]);

const {$t} = useSimpleLocale();

export function alert(options: AlertProps): Promise<void>;

export function alert(
    message: string,
    options?: Partial<AlertProps>,
): Promise<void>;

export function alert(
    message: string,
    title?: string,
    options?: Partial<AlertProps>,
): Promise<void>;

export function alert(
    arg0: AlertProps | string,
    arg1?: Partial<AlertProps> | string,
    arg2?: Partial<AlertProps>,
): Promise<void> {
    return new Promise((resolve, reject) => {
        const options: AlertProps = isString(arg0)
            ? {
                content: arg0,
            }
            : {...arg0};
        if (arg1) {
            if (isString(arg1)) {
                options.title = arg1;
            } else if (!isString(arg1)) {
                // 如果第二个参数是对象，则合并到选项中
                Object.assign(options, arg1);
            }
        }

        if (arg2 && !isString(arg2)) {
            Object.assign(options, arg2);
        }
        // 创建容器元素
        const container = document.createElement('div');
        document.body.append(container);

        // 创建一个引用，用于在回调中访问实例
        const alertRef = {container, instance: null as any};

        const props: AlertProps & Recordable<any> = {
            onClosed: (isConfirm: boolean) => {
                // 移除组件实例以及创建的所有dom（恢复页面到打开前的状态）
                // 从alerts数组中移除该实例
                alerts.value = alerts.value.filter((item) => item !== alertRef);

                // 从DOM中移除容器
                render(null, container);
                if (container.parentNode) {
                    container.remove();
                }

                // 解析 Promise，传递用户操作结果
                if (isConfirm) {
                    resolve();
                } else {
                    reject(new Error('dialog cancelled'));
                }
            },
            ...options,
            open: true,
            title: options.title ?? $t.value('prompt'),
        };

        // 创建Alert组件的VNode
        const vnode = h(Alert, props);

        // 渲染组件到容器
        render(vnode, container);

        // 保存组件实例引用
        alertRef.instance = vnode.component?.proxy as Component;

        // 将实例和容器添加到alerts数组中
        alerts.value.push(alertRef);
    });
}

export function confirm(options: AlertProps): Promise<void>;

export function confirm(
    message: string,
    options?: Partial<AlertProps>,
): Promise<void>;

export function confirm(
    message: string,
    title?: string,
    options?: Partial<AlertProps>,
): Promise<void>;

export function confirm(
    arg0: AlertProps | string,
    arg1?: Partial<AlertProps> | string,
    arg2?: Partial<AlertProps>,
): Promise<void> {
    const defaultProps: Partial<AlertProps> = {
        showCancel: true,
    };
    if (!arg1) {
        return isString(arg0)
            ? alert(arg0, defaultProps)
            : alert({...defaultProps, ...arg0});
    } else if (!arg2) {
        return isString(arg1)
            ? alert(arg0 as string, arg1, defaultProps)
            : alert(arg0 as string, {...defaultProps, ...arg1});
    }
    return alert(arg0 as string, arg1 as string, {
        ...defaultProps,
        ...arg2,
    });
}

export async function prompt<T = any>(
    options: PromptProps<T>,
): Promise<T | undefined> {
    const {
        component: _component,
        componentProps: _componentProps,
        componentSlots,
        content,
        defaultValue,
        modelPropName: _modelPropName,
        ...delegated
    } = options;

    const modelValue = ref<T | undefined>(defaultValue);
    const inputComponentRef = ref<null | VNode>(null);
    const staticContents: Component[] = [];

    staticContents.push(h(BasicRenderContent, { content, renderBr: true }));

    const modelPropName = _modelPropName || 'modelValue';
    const componentProps = {..._componentProps};

    // 每次渲染时都会重新计算的内容函数
    const contentRenderer = () => {
        const currentProps = {...componentProps};

        // 设置当前值
        currentProps[modelPropName] = modelValue.value;

        // 设置更新处理函数
        currentProps[`onUpdate:${modelPropName}`] = (val: T) => {
            modelValue.value = val;
        };

        // 创建输入组件
        inputComponentRef.value = h(
            _component || Input,
            currentProps,
            componentSlots,
        );

        // 返回包含静态内容和输入组件的数组
        return h(
            'div',
            {class: 'flex flex-col gap-2'},
            {default: () => [...staticContents, inputComponentRef.value]},
        );
    };

    const props: AlertProps & Recordable<any> = {
        ...delegated,
        async beforeClose(scope: BeforeCloseScope) {
            if (delegated.beforeClose) {
                return await delegated.beforeClose({
                    ...scope,
                    value: modelValue.value,
                });
            }
        },
        // 使用函数形式，每次渲染都会重新计算内容
        content: contentRenderer,
        contentMasking: true,
        async onOpened() {
            await nextTick();
            const componentRef: null | VNode = inputComponentRef.value;
            if (componentRef) {
                if (
                    componentRef.component?.exposed &&
                    isFunction(componentRef.component.exposed.focus)
                ) {
                    componentRef.component.exposed.focus();
                } else {
                    if (componentRef.el) {
                        if (
                            isFunction(componentRef.el.focus) &&
                            ['BUTTON', 'INPUT', 'SELECT', 'TEXTAREA'].includes(
                                componentRef.el.tagName,
                            )
                        ) {
                            componentRef.el.focus();
                        } else if (isFunction(componentRef.el.querySelector)) {
                            const focusableElement = componentRef.el.querySelector(
                                'input, select, textarea, button',
                            );
                            if (focusableElement && isFunction(focusableElement.focus)) {
                                focusableElement.focus();
                            }
                        } else if (
                            componentRef.el.nextElementSibling &&
                            isFunction(componentRef.el.nextElementSibling.focus)
                        ) {
                            componentRef.el.nextElementSibling.focus();
                        }
                    }
                }
            }
        },
    };

    await confirm(props);
    return modelValue.value;
}

export function clearAllAlerts() {
    alerts.value.forEach((alert) => {
        // 从DOM中移除容器
        render(null, alert.container);
        if (alert.container.parentNode) {
            alert.container.remove();
        }
    });
    alerts.value = [];
}
